package com.xc.xcrpc.server.tcp;

import com.xc.xcrpc.model.RpcRequest;
import com.xc.xcrpc.model.RpcResponse;
import com.xc.xcrpc.protocol.ProtocolMessage;
import com.xc.xcrpc.protocol.ProtocolMessageDecoder;
import com.xc.xcrpc.protocol.ProtocolMessageEncoder;
import com.xc.xcrpc.protocol.ProtocolMessageTypeEnum;
import com.xc.xcrpc.registry.LocalRegistry;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetSocket;

import java.io.IOException;
import java.lang.reflect.Method;

/**
 * 请求处理（服务提供者）
 * @author zqx
 * @since 2024/9/30
 */
public class TcpServerHandler implements Handler<NetSocket> {

    @Override
    public void handle(NetSocket netSocket) {

        TcpBufferHandlerWrapper bufferHandlerWrapper = new TcpBufferHandlerWrapper(buffer -> {
            //接收请求，解码
            ProtocolMessage<RpcRequest> protocolMessage;
            try{
                 protocolMessage = (ProtocolMessage<RpcRequest>) ProtocolMessageDecoder.decode(buffer);
            }catch (IOException e){
                throw new RuntimeException("协议消息解码错误");
            }
            RpcRequest rpcRequest = protocolMessage.getBody();

            //处理请求
            //构造响应结果对象
            RpcResponse rpcResponse = new RpcResponse();
            try{
                Class<?> implClass = LocalRegistry.get(rpcRequest.getServiceName());
                Method method = implClass.getMethod(rpcRequest.getMethodName(), rpcRequest.getParameterTypes());
                Object result = method.invoke(implClass.newInstance(), rpcRequest.getArgs());
                //封装返回结果
                rpcResponse.setData(result);
                rpcResponse.setDataType(method.getReturnType());
                rpcResponse.setMessage("ok");
            }catch (Exception e){
                e.printStackTrace();
                rpcResponse.setMessage(e.getMessage());
                rpcResponse.setException(e);
            }

            // 发送响应，编码
            ProtocolMessage.Header header = protocolMessage.getHeader();
            header.setType((byte) ProtocolMessageTypeEnum.RESPONSE.getKey());
            ProtocolMessage<RpcResponse> rpcResponseProtocolMessage = new ProtocolMessage<>(header, rpcResponse);
            try{
                Buffer encode = ProtocolMessageEncoder.encode(rpcResponseProtocolMessage);
                netSocket.write(encode);
            }catch (IOException e){
                throw new RuntimeException("协议消息编码错误");
            }
        });
        netSocket.handler(bufferHandlerWrapper);
    }
}

/**
 * todo 装饰器 24/9/30
 * TcpBufferHandlerWrapper 和 TcpServerHandler
 *
 * 网络数据处理时
 * 当网络数据到达并调用netSocket.handler(bufferHandlerWrapper);后：
 * 每次有新的Buffer数据到达时，会调用bufferHandlerWrapper的handle方法（因为TcpBufferHandlerWrapper实现了Handler<Buffer>接口）。
 * 在TcpBufferHandlerWrapper的handle方法中，会调用recordParser.handle(buffer)，将接收到的Buffer数据交给RecordParser处理。
 * RecordParser根据之前设置的逻辑（在initRecordParser方法中设置的输出处理器逻辑）处理Buffer数据，当处理到完整的消息时，
 * 会调用最初传入TcpBufferHandlerWrapper构造函数的bufferHandler（被装饰的Handler<Buffer>）来处理完整的消息。
 */

/**
 * 执行顺序分析
 * 是的，当netSocket.handler(bufferHandlerWrapper)被调用后，整个增强的逻辑就开始生效并按照以下顺序执行：
 * 初始数据接收与处理
 * 每次有数据到达netSocket时，数据以Buffer的形式被传递给bufferHandlerWrapper（TcpBufferHandlerWrapper类型）的handle方法。
 * 由于TcpBufferHandlerWrapper内部使用了RecordParser来处理半包和粘包问题，RecordParser会按照其内部逻辑（在initRecordParser方法中定义的逻辑）对Buffer数据进行解析。
 * 在RecordParser的处理过程中，当它确定接收到了完整的消息（通过解析消息头获取消息体长度，然后拼接完整的消息头和消息体）后，
 * 会调用最初传入TcpBufferHandlerWrapper构造函数中的Handler<Buffer>（也就是包含了你所列出的代码逻辑的lambda表达式部分）。
 * 包含的业务逻辑执行顺序
 * 接收请求，解码
 * 首先，执行ProtocolMessage<RpcRequest> protocolMessage = (ProtocolMessage<RpcRequest>) ProtocolMessageDecoder.decode(buffer);尝试对接收的Buffer进行解码，
 * 得到ProtocolMessage<RpcRequest>对象，如果解码过程中出现IOException则抛出运行时异常。然后通过RpcRequest rpcRequest = protocolMessage.getBody();获取RpcRequest对象。
 * 处理请求
 * 创建一个RpcResponse对象，然后根据RpcRequest中的serviceName从LocalRegistry获取对应的实现类（Class<?> implClass = LocalRegistry.get(rpcRequest.getServiceName());）。
 * 接着通过反射获取对应的方法（Method method = implClass.getMethod(rpcRequest.getMethodName(), rpcRequest.getParameterTypes());），
 * 并调用该方法（Object result = method.invoke(implClass.newInstance(), rpcRequest.getArgs());），如果在这个过程中出现异常则在RpcResponse中设置异常相关信息，
 * 否则将结果封装到RpcResponse中（rpcResponse.setData(result); rpcResponse.setDataType(method.getReturnType()); rpcResponse.setMessage("ok");）。
 * 发送响应，编码
 * 从之前解码得到的protocolMessage中获取Header，设置其类型为响应类型（header.setType((byte) ProtocolMessageTypeEnum.RESPONSE.getKey());），然后创建包含Header和RpcResponse的ProtocolMessage<RpcResponse>对象。接着对这个对象进行编码（Buffer encode = ProtocolMessageEncoder.encode(rpcResponseProtocolMessage);），最后将编码后的Buffer通过netSocket.write(encode)发送出去，如果编码过程中出现IOException则抛出运行时异常。
 */

/**
 * 自己总结的
 * 就是这个是先把这些装在一起，然后调用方法后，就增强了，和动态代理不一样，
 */